package org.mercworks.knight.util;

import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.PixelGrabber;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

public class ImageUtils
{
	/**
	 * Gets byte array representation of a file from the url of the file
	 * 
	 * @param file
	 *          the file
	 * @return a byte array representing the file
	 * @throws IOException
	 *           if there is an error accessing the file
	 */
	public static byte[] getBytesFromFile(URL url) throws IOException
	{
		byte[] bytes = null;
		List<Byte> listBytes = new ArrayList<Byte>();
		if (url != null)
		{
			InputStream is = url.openStream();
			
			int integerByte = 0;
			
			while((integerByte = is.read()) != -1)
			{
				Integer tempInteger = new Integer(integerByte);
				listBytes.add(tempInteger.byteValue());
			}
			// Close the input stream and return bytes
			is.close();
		}
		
		Object[] tempBytes = listBytes.toArray();
		int tempBytesLength = tempBytes.length;
		bytes = new byte[tempBytesLength];
		for(int index = 0; index < tempBytesLength; index++)
		{
			bytes[index] = ((Byte)tempBytes[index]).byteValue();
		}
		
		return bytes;
	}

	/**
	 * Load an image from file. Avoids the flaky MediaTracker/ImageObserver
	 * headache. Assumes that the file can be loaded quickly from the local
	 * filesystem, so does not need to wait in a thread. If it can't find the file
	 * in the filesystem, will try loading from jar file. If not found will return
	 * null.
	 * <P>
	 * 
	 * @param imageUrl
	 *          the URL of the image
	 */
	public static Image loadImageFromURL(URL imageUrl) throws Exception
	{
		if (imageUrl == null)
			throw new Exception("File not found");

		byte[] imageBytes = getBytesFromFile(imageUrl);

		Image image = null;
		int numTries = 20;
		
		if (imageBytes == null)
			throw new Exception("Image Not Found");
		else
		{
			image = Toolkit.getDefaultToolkit().createImage(imageBytes, 0,
					imageBytes.length);
			while (image.getWidth(null) < 0 && numTries-- > 0)
			{
				try
				{
					Thread.sleep(100);
				}
				catch (InterruptedException e)
				{
					System.out.println(e);
				}
			}
			while (image.getHeight(null) < 0 && numTries-- > 0)
			{
				try
				{
					Thread.sleep(100);
				}
				catch (InterruptedException e)
				{
					System.out.println(e);
				}
			}
		}
		return image;
	}

	/**
	 * Return the image pixels in default Java int ARGB format.
	 * 
	 * @return
	 */
	public static int[] getImagePixels(int[] pixels, Image image, int width,
			int height)
	{
		if (pixels == null && image != null)
		{
			pixels = new int[width * height];
			PixelGrabber pg = new PixelGrabber(image, 0, 0, width, height, pixels, 0,
					width);

			try
			{
				pg.grabPixels();
			}
			catch (Exception e)
			{
				System.out.println("Pixel Grabbing interrupted!");
				return null;
			}
		}

		return pixels;
	}

	/**
	 * Convert ARGB pixels to a ByteBuffer containing RGBA pixels.<BR>
	 * Can be drawn in ORTHO mode using:<BR>
	 * GL.glDrawPixels(imgW, imgH, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, byteBuffer); <BR>
	 * If flipVertically is true, pixels will be flipped vertically (for OpenGL
	 * coord system).
	 * 
	 * @param imgFilename
	 * @return ByteBuffer
	 */
	public static ByteBuffer convertImagePixels(int[] jpixels, int imgw,
			int imgh, boolean flipVertically)
	{
		byte[] bytes; // will hold pixels as RGBA bytes
		if (flipVertically)
		{
			jpixels = flipPixels(jpixels, imgw, imgh); // flip Y axis
		}
		bytes = convertARGBtoRGBA(jpixels);
		return AllocationUtil.allocBytes(bytes); // convert to ByteBuffer and return
	}

	/**
	 * Convert pixels from java default ARGB int format to byte array in RGBA
	 * format.
	 * 
	 * @param jpixels
	 * @return
	 */
	private static byte[] convertARGBtoRGBA(int[] jpixels)
	{
		byte[] bytes = new byte[jpixels.length * 4]; // will hold pixels as RGBA
		// bytes
		int p, r, g, b, a;
		int j = 0;
		for (int i = 0; i < jpixels.length; i++)
		{
			p = jpixels[i];
			a = (p >> 24) & 0xFF; // get pixel bytes in ARGB order
			r = (p >> 16) & 0xFF;
			g = (p >> 8) & 0xFF;
			b = (p >> 0) & 0xFF;
			bytes[j + 0] = (byte) r; // fill in bytes in RGBA order
			bytes[j + 1] = (byte) g;
			bytes[j + 2] = (byte) b;
			bytes[j + 3] = (byte) a;
			j += 4;
		}
		return bytes;
	}

	/**
	 * Flip an array of pixels vertically
	 * 
	 * @param imgPixels
	 * @param imgw
	 * @param imgh
	 * @return int[]
	 */
	private static int[] flipPixels(int[] imgPixels, int imgw, int imgh)
	{
		int[] flippedPixels = null;
		if (imgPixels != null)
		{
			flippedPixels = new int[imgw * imgh];
			for (int y = 0; y < imgh; y++)
			{
				for (int x = 0; x < imgw; x++)
				{
					flippedPixels[((imgh - y - 1) * imgw) + x] = imgPixels[(y * imgw) + x];
				}
			}
		}
		return flippedPixels;
	}

}
